package models

import (
	"errors"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/logs"
	"time"
)

// Menu 菜单权限
type Menu struct {
	Id          int64
	MenuName    string
	MenuNo      string
	SuperMenuNo string
	Path        string
	IsDefault   bool      `orm:"default(0)" json:"isDefault"`
	CreateTime  time.Time `orm:"auto_now_add;null"`
	UpdateTime  time.Time `orm:"auto_now;null"`
	IsDelete    bool      `orm:"default(0)" json:"-"`
	Users       []*User   `orm:"rel(m2m)" json:"-"`
}

type MenuTreeItem struct {
	Title    string          `json:"title"`
	Key      string          `json:"key"`
	Path     string          `json:"path"`
	Children []*MenuTreeItem `json:"children"`
}

func (menu *Menu) TableName() string {
	return "t_menu"
}

func NewMenu() *Menu {
	return &Menu{}
}

// Save 保存
func (menu *Menu) Save() (int64, error) {
	o := orm.NewOrm()
	return o.Insert(menu)
}

// Update 更新指定字段
func (menu *Menu) Update(cols ...string) (int64, error) {
	o := orm.NewOrm()
	return o.Update(menu, cols...)
}

// Delete 删除
func (menu *Menu) Delete() (int64, error) {
	o := orm.NewOrm()
	return o.Delete(menu)
}

// DelLogic 逻辑删除
func (menu *Menu) DelLogic() error {
	if menu.Id < 1 {
		return nil
	}
	o := orm.NewOrm()
	_, err := o.QueryTable(menu).Filter(IdColumnName, menu.Id).Update(orm.Params{
		"is_delete": 1,
	})
	return err
}

// GetById 根据id获取
func (menu *Menu) GetById() error {
	o := orm.NewOrm()
	return o.Read(menu)
}

// GetBySuperMenuNo 获取子节点
func (menu *Menu) GetBySuperMenuNo(superMenuNo string) ([]*Menu, int64, error) {
	var res []*Menu
	o := orm.NewOrm()
	count, err := o.QueryTable(menu).Filter("super_menu_no__eq", superMenuNo).All(&res)
	return res, count, err
}

// GetByMenuNo 通过菜单编号获取菜单数据
func GetByMenuNo(menuNo string) *Menu {
	menu := NewMenu()
	o := orm.NewOrm()
	err := o.QueryTable(menu).Filter("menu_no", menuNo).One(menu)
	if err != nil {
		return nil
	}
	return menu
}

// GetMenuTreeOfAll 获取所有菜单权限组成的菜单权限树
func GetMenuTreeOfAll() (*MenuTreeItem, error) {
	var temp []*Menu
	o := orm.NewOrm()
	num, err := o.QueryTable(Menu{}).All(&temp)
	if err != nil && num < 1 {
		return nil, err
	}
	return BuildSingleRootMenuTree(temp)
}

func GetDefaultMenuNo() []string {
	var menuList []*Menu
	o := orm.NewOrm()
	_, err := o.QueryTable(NewMenu()).Filter("is_default", 1).All(&menuList, "menu_no")
	if err != nil {
		logs.Error(err)
		return nil
	}
	res := make([]string, len(menuList))
	for index, menu := range menuList {
		res[index] = menu.MenuNo
	}
	return res
}

// BuildSingleRootMenuTree 组装单root节点菜单树
func BuildSingleRootMenuTree(menuList []*Menu) (*MenuTreeItem, error) {
	tempMap := make(map[string]*MenuTreeItem, len(menuList))
	var root *MenuTreeItem
	for _, menu := range menuList {
		menuTreeItem := MenuTreeItem{
			Title:    menu.MenuName,
			Key:      menu.MenuNo,
			Path:     menu.Path,
			Children: nil,
		}
		// 获取根节点
		if menu.SuperMenuNo == "" {
			root = &menuTreeItem
		}
		tempMap[menuTreeItem.Key] = &menuTreeItem
	}
	if root == nil {
		root = GetMenuRoot()
		if root == nil {
			return nil, errors.New("根目录不存在")
		}
	}
	// 开始组装目录树
	for _, menu := range menuList {
		if menu.MenuNo == root.Key {
			continue
		}
		arriveRoot := menu.SuperMenuNo == root.Key
		if arriveRoot {
			if !isAdded2Root(tempMap[menu.MenuNo].Key, root) {
				root.Children = append(root.Children, tempMap[menu.MenuNo])
			}
			continue
		}
		temMenu := menu
		for !arriveRoot {
			// 获取父节点
			superMenu := GetByMenuNo(temMenu.SuperMenuNo)
			superMenuTreeItem := getSuperMenuItem(tempMap, superMenu)
			if superMenuTreeItem.Children == nil {
				superMenuTreeItem.Children = []*MenuTreeItem{}
			}

			isContains := false
			for _, child := range superMenuTreeItem.Children {
				if child.Key == tempMap[menu.MenuNo].Key {
					isContains = true
					break
				}
			}
			if !isContains {
				superMenuTreeItem.Children = append(superMenuTreeItem.Children, tempMap[menu.MenuNo])
			}
			tempMap[superMenu.MenuNo] = superMenuTreeItem
			arriveRoot = superMenu.SuperMenuNo == root.Key
			if arriveRoot {
				if !isAdded2Root(superMenuTreeItem.Key, root) {
					root.Children = append(root.Children, superMenuTreeItem)
				}
			} else {
				temMenu = superMenu
			}
		}
	}
	return root, nil
}

// 根据父菜单编号获取父菜单树结点
func getSuperMenuItem(menuItemStore map[string]*MenuTreeItem, superMenu *Menu) *MenuTreeItem {
	superMenuTreeItem := menuItemStore[superMenu.MenuNo]
	if superMenuTreeItem == nil {
		superMenuTreeItem = &MenuTreeItem{
			Title:    superMenu.MenuName,
			Key:      superMenu.MenuNo,
			Path:     superMenu.Path,
			Children: nil,
		}
	}
	return superMenuTreeItem
}

// 判断给定的菜单编号是否加入了root的子节点
func isAdded2Root(menuNo string, root *MenuTreeItem) bool {
	isAdded := false
	for _, child := range root.Children {
		if child.Key == menuNo {
			isAdded = true
		}
	}
	return isAdded
}

// GetMenuRoot 获取菜单根目录
func GetMenuRoot() *MenuTreeItem {
	o := orm.NewOrm()
	rootMenu := NewMenu()
	err := o.QueryTable(rootMenu).Filter("super_menu_no", "").One(rootMenu)
	if err != nil {
		return nil
	}
	return &MenuTreeItem{
		Title:    rootMenu.MenuName,
		Key:      rootMenu.MenuNo,
		Path:     rootMenu.Path,
		Children: nil,
	}
}
